<?php

/**
 * View helper for grid output
 *
 * @category Ext
 * @package  View_Helper
 */
class Ext_View_Helper_Grid extends Zend_View_Helper_HtmlElement
{

    /**
     *
     * @var Ext_Grid
     */
    protected $_grid = null;

    /**
     *
     * @return Ext_Grid
     */
    public function getGrid()
    {
        if (!$this->_grid) {
            throw new Ext_View_Exception('Ext_View_Helper_Grid');
        }
        return $this->_grid;
    }

    /**
     *
     * @return Ext_View_Helper_Grid
     */
    public function setGrid(Ext_Grid $grid)
    {
        $this->_grid = $grid;
        return $this;
    }

    /**
     *
     * @param Ext_Grid $grid
     * @return string
     */
    public function grid(Ext_Grid $grid)
    {
        $this->_grid = $grid;

        $paginator  = $grid->getPaginator();
        $columns    = $grid->getColumns();
        $result     = '';


        $result = $this->_renderHeader();;
        if ($this->getGrid()->isFiltersEnabled()) {
            $result .= $this->_renderFilters();
        }
        $result .= $this->_renderBody();


        $table = $this->_table($result);

        return $table;
    }

    /**
     * Render grid header
     *
     * @return string
     */
    protected function _renderHeader()
    {
        $headerCells = '';

        if ($this->getGrid()->isMassActionEnabled()) {
            $headerCells .= $this->_renderHeaderCell(array(
                'header' => ''
            ));
        }

        foreach ($this->getGrid()->getColumns() as $column) {
            $headerCells .= $this->_renderHeaderCell($column);
        }

        return $this->_row($headerCells);
    }

    /**
     * Render grig body
     *
     * @return string
     */
    protected function _renderBody()
    {
        $result = '';

        foreach ($this->getGrid()->getPaginator() as $entity) {

            $cells = '';

            if (!is_object($entity) && !is_array($entity)) {
                throw new Zend_View_Exception('Data row expected to be an object or an array');
            }

            $id = $this->_getFieldValue($this->getGrid()->getMassActionsId(), $entity);;

            if ($this->getGrid()->isMassActionEnabled()) {
                $cells .= $this->_cell($this->_checkBox($id));
            }

            foreach ($this->getGrid()->getColumns() as $column) {
                $cells .= $this->_renderBodyCell($column, $entity);
            }

            $result .= $this->_row($cells);
        }

        return $result;
    }

    /**
     * Render filters
     *
     * @return string
     */
    protected function _renderFilters()
    {
        $filterCells = '';

        if ($this->getGrid()->isMassActionEnabled()) {
            $filterCells .= $this->_cell('');
        }

        foreach ($this->getGrid()->getColumns() as $column) {
            $filterCells .= $this->_renderFilterCell($column);
        }

        return $this->_row($filterCells);
    }

    protected function _renderHeaderCell($column)
    {
        $dir        = null;
        $arrow      = null;
        $sortable   = false;

        if (isset($column['sortable']) && $column['sortable']) {

            $sortable = true;

            $sortColumn = $this->getGrid()->getSortColumn();

            if ($sortColumn && ($column['field'] == $sortColumn)) {
                if ($this->getGrid()->getSortDirection() == 'asc') {
                    $dir   = 'desc';
                    $arrow = 'asc';
                } else {
                    $dir   = 'asc';
                    $arrow = 'desc';
                }
            } else {
                $dir   = 'asc';
                $arrow = null;
            }
        }

        $partial = $this->getGrid()->getPartials();

        return $this->view->partial($partial['header'], array(
            'value'     => $this->view->translate($column['header']),
            'sortable'  => $sortable,
            'sort'      => !empty($column['field']) ? $column['field'] : null,
            'dir'       => $dir,
            'arrow'     => $arrow
        ));
    }

    protected function _renderFilterCell($column)
    {
        $value = '';

        $partials = $this->getGrid()->getPartials();

        if (isset($column['filter'])) {

            $data = array(
                'name'  => $column['field'],
                'type'  => $column['filter'],
                'value' => $this->getGrid()->getFilterValue($column['field'])
            );

            if ('select' == $column['filter']) {

                if (!isset ($column['filter_options'])) {
                    $column['filter_options'] = array();
                }

                $data['filter_options'] = $column['filter_options'];
            }

            $value = $this->view->partial($partials['filter'], $data);
        }

        return $this->_cell($value);
    }

    protected function _renderBodyCell($column, $data)
    {
        $value = '';

        if (isset($column['actions'])) {

            $value = $this->_renderActions($column['actions'], $data);

        } elseif (isset($column['callback'])) {

            $callback = "_{$column['callback']}Callback";
            $value = $this->getGrid()->$callback($data);

        } else {

            $value = $this->_getFieldValue($column['field'], $data);
        }

        if (!empty($column['helpers'])) {
            $value = $this->_applyHelpers($column['helpers'], $value);
        }

        return $this->_cell($value);
    }

    protected function _cell($value, $align = 'left')
    {
        $partial = $this->getGrid()->getPartials();

        return $this->view->partial($partial['cell'], array(
            'value' => $value
        ));
    }

    protected function _row($cells)
    {
        $partial = $this->getGrid()->getPartials();

        return $this->view->partial($partial['row'], array(
            'cells' => $cells
        ));
    }

    protected function _renderMassActions()
    {
        $partial = $this->getGrid()->getPartials();

        return $this->view->partial($partial['actions'], array(
            'massActions' => $this->getGrid()->getMassActions()
        ));
    }

    protected function _table($rows)
    {
        $partial = $this->getGrid()->getPartials();

        $massActions = '';

        if ($this->getGrid()->isMassActionEnabled()) {
            $massActions = $this->_renderMassActions();
        }

        return $this->view->partial($partial['table'], array(
            'rows'                  => $rows,
            'massActions'           => $massActions,
            'paginator'             => $this->getGrid()->getPaginator(),
            'paginationEnabled'     => $this->getGrid()->isPaginationEnabled(),
            'filtersEnabled'        => $this->getGrid()->isFiltersEnabled(),
            'massActionEnabled'     => $this->getGrid()->isMassActionEnabled(),
            'perPageOptions'        => $this->getGrid()->getPerPageOptions()
        ));
    }

    protected function _checkBox($value)
    {
        $partial = $this->getGrid()->getPartials();

        return $this->view->partial($partial['checkBox'], array(
            'value' => $value
        ));
    }

    protected function _getFieldValue($field, $entity)
    {
        if (is_object($entity)) {
            return $entity->$field;
        }
        return isset($entity[$field]) ? $entity[$field] : '';
    }

    /**
     * Apply view helpers for grid's cell content
     *
     * @param array|string $column
     * @param mixed $value
     * @return string
     */
    protected function _applyHelpers($column, $value)
    {
        if (!is_array($column)) {
            $column = array($column);
        }
        foreach ($column as $helper => $options) {
            if (is_numeric($helper)) {
                $helper = $options;
                $options = array('%value%');
            }

            $key = array_search('%value%', $options);

            $options[$key] = $value;

            $value = call_user_func_array(array($this->view, $helper), $options);
        }
        return $value;
    }

    /**
     * Render action links
     *
     * @param array $actions
     * @param array $data
     * @return string
     */
    protected function _renderActions(array $actions, $data)
    {
        $request = $this->getGrid()->getRequest();

        $routeParams = array(
            $request->getModuleKey(),
            $request->getControllerKey(),
            $request->getActionKey()
        );

        $results = array();
        foreach ($actions as $action) {
            if (isset($action['callback'])) {
                $callback = "_{$action['callback']}Callback";

                $actionHtml = $this->getGrid()->$callback($data);
            } else {
                if (!isset($action['route'])) {
                    $action['route'] = 'default';
                }
                if (!isset($action['reset'])) {
                    $action['reset'] = true;
                }

                foreach ($action['url'] as $key => &$value) {
                    if (isset($data[$value]) && !in_array($value, $routeParams)) {
                        $value = $data[$value];
                    }
                }

                $actionHtml = '<a href="' . $this->view->url($action['url'], $action['route'], $action['reset']) . '">'
                        . $this->view->translate($action['label']) . '</a>';
            }
            $results[] = $actionHtml;
        }

        return implode(' | ', $results);
    }
}